package com.jdh.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory;

import java.util.List;

/**
 * @ClassName: WebsocketConfig
 * @Author: jdh
 * @CreateTime: 2022-11-17
 * @Description: websocket + stomp 的相关配置类
 */
@Configuration
@ConditionalOnProperty(prefix = "autoconfigure", value = "mq_enabled", havingValue = "false", matchIfMissing = true)
@EnableWebSocketMessageBroker //使能STOMP协议来传输基于代理（MessageBroker）的消息;controller就支持@MessageMapping,就像是使用@requestMapping一样。
@Slf4j
public class WebsocketConfig implements WebSocketMessageBrokerConfigurer {

    /**
     * 配置消息代理
     * @param config 消息代理注册对象配置
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        log.info("========= websocket + stomp =========");
        // 自定义调度器，用于控制心跳线程
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 线程池线程数，心跳连接开线程
        taskScheduler.setPoolSize(1);
        // 线程名前缀
        taskScheduler.setThreadNamePrefix("websocket-heartbeat-thread-");
        // 初始化
        taskScheduler.initialize();

        // 配置服务端推送消息给客户端的代理路径
        config.enableSimpleBroker("/topic", "/own","/websocket")
                .setHeartbeatValue(new long[]{15000, 15000})
                .setTaskScheduler(taskScheduler)
        ; // 定义消息代理前缀
        // 客户端向服务端发送消息需有/app 前缀
        config.setApplicationDestinationPrefixes("/app"); // 定义消息请求前缀
        // 指定用户发送（一对一）的前缀 /user 不配置的话，默认是 /user
        config.setUserDestinationPrefix("/user");

    }

    /**
     * 注册stomp端点
     * @param registry stomp端点注册对象
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/chat") // 注册一个 WebSocket 端点  客户端连接地址ws://127.0.0.1:8097/chat
                .setAllowedOrigins("*");
//                .withSockJS(); // 支持 SockJS
    }

    /**
     * 采用自定义拦截器，获取connect时候传递的参数
     * 使用客户端绑定配置，
     * @param registration
     */
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new AuthChannelInterceptor());

    }



    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
        registry.setSendTimeLimit(15000) // 发送消息时间限制
                .setSendBufferSizeLimit(512 * 1024) // 发送缓冲区大小限制
                .setMessageSizeLimit(1024 * 1024); // 消息大小限制

//        registry.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
//            @Override
//            public WebSocketHandler decorate(WebSocketHandler handler) {
//                return null;
//            }
//        });
    }

    public static class AuthChannelInterceptor implements ChannelInterceptor {
        /**
         * 连接前监听
         *
         * @param message
         * @param channel
         * @return
         */
        @Override
        public Message<?> preSend(Message<?> message, MessageChannel channel) {
            StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
//            System.out.println("连接信息:" + accessor);
            System.out.println("perSend => message:" + message + "; channel:" + channel);
            //不是首次连接，已经登陆成功
            return message;
        }

        @Override
        public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
            System.out.println("postSend => message:" + message + "; channel:" + channel + "; sent:" + sent);
        }
    }


}
